import math
import random
import re
import socket
import time

from host import host
from gevent import monkey;monkey.patch_all()
import cv2
import gevent
import numpy as np
import select
from flask import Flask, render_template, request, session, redirect, url_for
from flask_socketio import SocketIO
from gevent import spawn
from decode import h264_decode
from udp import udp_client2, udp_client3, udp_client4, udp_client7, udp_client8, udp_client10

app = Flask(__name__, static_folder='static')
# 设置密钥
app.config['SECRET_KEY'] = 'qhl'
# 会话持续时间/s
app.config['PERMANENT_SESSION_LIFETIME'] = 30
# 绑定socketio与应用
socketio = SocketIO(app, cors_allowed_origins="*", async_mode='gevent')

online_user = []    # 在线用户名单
flag = 0            # 是否处于rc运动


@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'GET':
        if 'username' in session:
            return redirect(url_for('chat'))
        return render_template('index.html')
    else:
        username = request.form.get('username')
        session['username'] = username
        return redirect(url_for('chat'))


@app.route('/chat/')
def chat():
    if 'username' in session:
        username = session['username']
        return render_template('live.html', username=username)
    else:
        return redirect(url_for('index'))


@app.route('/logout/')
def logout():
    if 'username' in session:
        session.clear()
    print(len(online_user))
    return redirect(url_for('index'))


@socketio.on('connect')
def handle_connect():
    username = session.get('username')
    spawn(online_user_update, username)


# 获得视频流
def generate():
    """发送接收到的视频流给web"""
    start_time = time.time()
    frame_count = 0
    while True:
        data, addr = udp_client2.recvfrom(4096)
        udp_client8.sendto(data, (host, 3000))
        frames = h264_decode(b'' + data)
        for frame in frames:
            frame = np.array(frame)
            ret, buffer = cv2.imencode('.jpg', frame)
            frame_bytes = buffer.tobytes()
            socketio.emit('video_feed', {
                'data': frame_bytes
            })
            frame_count += 1
            # 每秒计算一下帧率
            if time.time() - start_time >= 1:
                print("Frame rate: ", frame_count)
                frame_count = 0
                start_time = time.time()


def recv_action():
    """接收运动信息，进一步处理后发送给web绘制路径"""
    now_x = 0       # 无人机此时位置，以无人机初始位置为坐标系
    now_y = 0

    while True:
        data, addr = udp_client4.recvfrom(4096)
        data = data.decode().strip()

        all_displacement_x = float(re.findall(r'x:(-?\d+)', data)[0])
        all_displacement_y = float(re.findall(r'y:(-?\d+)', data)[0])
        all_displacement_z = float(re.findall(r'z:(-?\d+)', data)[0])
        all_displacement = math.sqrt(all_displacement_x * all_displacement_x + all_displacement_y * all_displacement_y + all_displacement_z * all_displacement_z)
        speed = float(re.findall(r'speed:(-?\d+)', data)[0])
        speed_x = re.findall(r'speed_x:(-?\d+)', data)
        speed_y = re.findall(r'speed_y:(-?\d+)', data)
        if speed_x:     # 如果是rc函数
            global flag
            flag = 0
            frame_time = 0.01
            while flag == 0:
                now_x = now_x + speed_x * frame_time
                now_y = now_y + speed_y * frame_time
                socketio.emit('position', {
                    'x': now_x / 10,
                    'z': now_y / 10
                })
                time.sleep(frame_time -0.008)
        else:           # 如果不是rc函数
            all_time = all_displacement / speed
            action_time = 0
            remain_time = all_time
            frame_time = 0.01
            while remain_time > 0:
                action_time = action_time + frame_time
                remain_time = remain_time - frame_time
                now_x = now_x + all_displacement_x / all_time * frame_time
                now_y = now_y + all_displacement_y / all_time * frame_time
                socketio.emit('position', {
                    'x': now_x / 10,
                    'z': now_y / 10
                })
                time.sleep(frame_time -0.008)


def recv_stop():
    """接收stop命令，停止rc运动"""
    while True:
        global flag
        data = udp_client7.recvfrom(4096)
        flag = 1


def recv_recognition():
    """接收识别circle障碍物的结果然后发送该障碍物的坐标给web"""
    while True:
        data, addr = udp_client10.recvfrom(4096)
        data = data.decode().strip()
        x = int(re.findall(r'x:(-?\d+)', data)[0])
        y = int(re.findall(r'y:(-?\d+)', data)[0])
        r = int(re.findall(r'r:(-?\d+)', data)[0])
        socketio.emit('circle', {
            'x': x/30,
            'y': y/30,
            'distance': r/30
        })


def online_user_update(username):
    online_user.append(username)
    socketio.emit('online users', {'count': len(online_user)})


def send_data():
    """发送接收到的状态信息给web"""
    while True:
        try:
            data, addr = udp_client3.recvfrom(4096)
            data = data.decode().strip()
        except socket.timeout as e:
            print("Timeout!")
            data = None
        if data is not None:
            mid = re.findall(r'mid:(-?\d+)', data)[0]
            x = re.findall(r'x:(-?\d+)', data)[0]
            y = re.findall(r'y:(-?\d+)', data)[0]
            z = re.findall(r'z:(-?\d+)', data)[0]
            mpry = re.findall(r'mpry:(-?\d+)', data)[0]
            pitch = int(re.findall(r'pitch:(-?\d+)', data)[0])
            roll = int(re.findall(r'roll:(-?\d+)', data)[0])
            yaw = int(re.findall(r'yaw:(-?\d+)', data)[0])
            vgx = int(re.findall(r'vgx:(-?\d+)', data)[0])
            vgy = int(re.findall(r'vgy:(-?\d+)', data)[0])
            vgz = int(re.findall(r'vgz:(-?\d+)', data)[0])
            templ = re.findall(r'templ:(-?\d+)', data)[0]
            temph = re.findall(r'temph:(-?\d+)', data)[0]
            tof = int(re.findall(r'tof:(-?\d+)', data)[0])*10
            height = re.findall(r'h:(-?\d+)', data)[0]
            battery = re.findall(r'bat:(-?\d+)', data)[0]
            baro = re.findall(r'baro:(-?\d+)', data)[0]
            time = re.findall(r'time:(-?\d+)', data)[0]
            agx = int(re.findall(r'agx:(-?\d+)', data)[0])
            agy = int(re.findall(r'agy:(-?\d+)', data)[0])
            agz = int(re.findall(r'agz:(-?\d+)', data)[0])
            # print("电量" + battery)
            # print("温度" + templ + "~" + temph)
            # print("速度", vgx, vgy, vgz)
            # print("高度" + height)
            # # print("信噪比" + string5)
            # print("电机运转时间" + time)
            # print("加速度", agx, agy, agz)
            # print("tof高度", tof)
            # print("俯仰、横滚、偏航角:", pitch, roll, yaw)
            socketio.emit('get data', {
                'battery': battery,  # 电量*
                'templ': templ,  # 温度*
                'temph': temph,
                'tof': tof,  # tof高度*
                'height': height,
                'time': time,
                'agx': agx,  # ax*
                'agy': agy,  # ay*
                'agz': agz,  # az*
                'pitch': pitch,  # 横滚*
                'roll': roll,  # 翻转*
                'yaw': yaw,  # 偏航角*
            })
            socketio.emit('fly_data', {
                'tof': tof,  # tof高度*
                'vgx': vgx,
                'vgy': vgy,
                'vgz': vgz,
                'agx': agx,  # ax*
                'agy': agy,  # ay*
                'agz': agz,  # az*
                'pitch': pitch,  # 横滚*
                'roll': roll,  # 翻转*
                'yaw': yaw,  # 偏航角*
            })
            socketio.emit('direction', {
                'pitch': pitch,
                'roll': roll,
                'yaw': yaw,
                'tof': tof/100
            })


@socketio.on('join')
def on_join(data):
    spawn(join_message, data)


def join_message(data):
    username = data.get('username')
    socketio.emit('connect info', username + '欢迎来到直播间')


@socketio.on('send msg')
def handle_message(data):
    spawn(emit_message, data)


def emit_message(data):
    data['message'] = data.get('message').replace('<', '&lt;').replace('>', '&gt;').replace(' ', '&nbsp;')
    socketio.emit('send msg', data)


@socketio.on('send gift')
def handle_lift(data):
    spawn(send_gift, data)


def send_gift(data):
    username = data.get('username')
    giftname = data.get('giftname')
    socketio.emit('send gift', username + '送出' + giftname)


@socketio.on('leave')
def on_leave(data):
    spawn(user_leave, data)


def user_leave(data):
    username = data.get('username')
    online_user.remove(username)
    socketio.emit('online users', {'count':len(online_user)})
    socketio.emit('connect info', username + '离开直播间')


if __name__ == '__main__':
    # 开启五个死循环协程
    spawn(recv_action)
    spawn(generate)
    spawn(send_data)
    spawn(recv_stop)
    spawn(recv_recognition)
    # 使用0.0.0.0来绑定所有可用的网络接口，从而使应用可以在局域网内的任何计算机上访问：
    socketio.run(app, host='0.0.0.0', port=5000, debug=False)


